package com.hsurosy.domain.activity.service.partake;

import com.alibaba.fastjson.JSON;
import com.hsurosy.domain.activity.model.aggregate.CreatePartakeOrderAggregate;
import com.hsurosy.domain.activity.model.entity.ActivityEntity;
import com.hsurosy.domain.activity.model.entity.PartakeRaffleActivityEntity;
import com.hsurosy.domain.activity.model.entity.UserRaffleOrderEntity;
import com.hsurosy.domain.activity.model.valobj.ActivityStateVO;
import com.hsurosy.domain.activity.repository.IActivityRepository;
import com.hsurosy.domain.activity.service.IRaffleActivityPartakeService;
import com.hsurosy.types.enums.ResponseCode;
import com.hsurosy.types.exception.AppException;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;

/**
 * @Author Hsu琛君珩
 * @Date 2024-11-10 14:53
 * @Description 抽奖活动参与抽奖类
 * @Version: v1.0.0
 */
@Slf4j
public abstract class AbstractRaffleActivityPartake implements IRaffleActivityPartakeService {

    protected final IActivityRepository activityRepository; // 活动仓库接口

    public AbstractRaffleActivityPartake(IActivityRepository activityRepository) {
        this.activityRepository = activityRepository;
    }

    /**
     * 创建用户参与抽奖活动的订单
     *
     * @param userId 用户ID，用于标识参与活动的用户
     * @param activityId 活动ID，用于标识用户参与的具体活动
     * @return 创建的抽奖订单实体对象 `UserRaffleOrderEntity`
     */
    @Override
    public UserRaffleOrderEntity createOrder(String userId, Long activityId) {
        return createOrder(PartakeRaffleActivityEntity.builder()
                .userId(userId) // 用户ID
                .activityId(activityId) // 活动ID
                .build());
    }

    /**
     * 创建抽奖参与订单
     * 1. 检查活动状态和时间是否有效；
     * 2. 如果存在未消费订单，则直接返回；
     * 3. 否则根据账户信息构建订单，并保存订单聚合对象。
     *
     * @param partakeRaffleActivityEntity 包含用户参与活动的基本信息。
     * @return 返回生成的抽奖订单实体。
     */
    @Override
    public UserRaffleOrderEntity createOrder(PartakeRaffleActivityEntity partakeRaffleActivityEntity) {
        // 0. 初始化基础信息
        String userId = partakeRaffleActivityEntity.getUserId();
        Long activityId = partakeRaffleActivityEntity.getActivityId();
        Date currentDate = new Date();

        log.info("创建活动抽奖单开始 userId: {} activityId: {}", userId, activityId);
        // 1. 查询活动信息
        ActivityEntity activityEntity = activityRepository.queryRaffleActivityByActivityId(activityId);

        // 校验活动状态是否有效
        if (!ActivityStateVO.open.equals(activityEntity.getState())) {
            log.error("创建活动抽奖单失败，活动状态未开启 activityId: {} state: {}", activityId, activityEntity.getState());
            throw new AppException(ResponseCode.ACTIVITY_STATE_ERROR.getCode(), ResponseCode.ACTIVITY_STATE_ERROR.getInfo());
        }
        // 校验活动时间是否在有效期内「开始时间 <- 当前时间 -> 结束时间」
        if (activityEntity.getBeginDateTime().after(currentDate) || activityEntity.getEndDateTime().before(currentDate)) {
            throw new AppException(ResponseCode.ACTIVITY_DATE_ERROR.getCode(), ResponseCode.ACTIVITY_DATE_ERROR.getInfo());
        }

        // 2. 查询是否存在未被使用的抽奖订单记录
        UserRaffleOrderEntity userRaffleOrderEntity = activityRepository.queryNoUsedRaffleOrder(partakeRaffleActivityEntity);
        if (null != userRaffleOrderEntity) {
            log.info("创建参与活动订单存在 userId: {} activityId: {} userRaffleOrderEntity: {}", userId, activityId, JSON.toJSONString(userRaffleOrderEntity));
            return userRaffleOrderEntity;
        }

        // 3. 账户额度检查并返回账户额度构建对象
        CreatePartakeOrderAggregate createPartakeOrderAggregate = this.doFilterAccount(userId, activityId, currentDate);

        // 4. 构建新的用户抽奖订单
        UserRaffleOrderEntity userRaffleOrder =  this.buildUserRaffleOrder(userId, activityId, currentDate);

        // 5. 将抽奖订单填充到聚合对象中
        createPartakeOrderAggregate.setUserRaffleOrderEntity(userRaffleOrder);

        // 6. 保存订单聚合对象，确保领域内的事务一致性
        activityRepository.saveCreatePartakeOrderAggregate(createPartakeOrderAggregate);
        log.info("创建活动抽奖单完成 userId: {} activityId: {} orderId: {}", userId, activityId, userRaffleOrder.getOrderId());

        return userRaffleOrder;
    }

    protected abstract CreatePartakeOrderAggregate doFilterAccount(String userId, Long activityId, Date currentDate);

    protected abstract UserRaffleOrderEntity buildUserRaffleOrder(String userId, Long activityId, Date currentDate);

}
